package org.newcih.util;

import com.github.jaiimageio.plugins.tiff.TIFFImageWriteParam;
import org.newcih.pojo.Box;
import org.newcih.pojo.BoxRow;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import static net.sourceforge.tess4j.util.ImageIOHelper.getIIOImageList;

/**
 * 图像处理工具
 *
 * @author newcih
 * @version 2018-01-26
 */
public class ImageUtils {

    /**
     * 图片文件格式
     */
    public static final String TIF = "tif";

    /**
     * tif文件名分割符
     */
    public static final String TIF_FILENAME_SEPARATOR_CHAR = "@";


    /**
     * 图片格式转换为tif
     *
     * @param fileName 转换后的tif文件名
     * @param image    待转换文件
     */
    public static boolean convert(String fileName, BufferedImage image) {
        File              tiffFile = new File(fileName);
        ImageOutputStream ios      = null;
        ImageWriter       writer   = null;

        try {
            Iterator iterator = ImageIO.getImageWritersByFormatName(TIF);
            if (iterator.hasNext()) {
                writer = (ImageWriter) iterator.next();
            } else {
                return false;
            }
            // 开始写入tif文件
            ios = ImageIO.createImageOutputStream(tiffFile);
            writer.setOutput(ios);
            TIFFImageWriteParam writeParam = new TIFFImageWriteParam(Locale.ENGLISH);
            writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            writeParam.setCompressionType("PackBits");
            IIOImage iioImage = new IIOImage(image, null, null);
            writer.write(null, iioImage, writeParam);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 读取tiff文件到BufferedImage
     *
     * @param tiffFile 待读取的tiff图片
     * @return
     */
    public static BufferedImage load(File tiffFile) {
        ImageReader          reader = null;
        FileImageInputStream fis    = null;
        BufferedImage        res    = null;

        try {
            return null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 合并多个tiff文件，同时返回生成的box文件，该文件的数据来源如下
     * 1，value值来源于用户提供
     * 2，坐标及范围来源于图片大小
     *
     * @param data     用户提供的数据，包含图片及其对应的值
     * @param destFile 生成的目标tiff文件
     * @return 自定义生成的box对象
     */
    public static Box mergeMultiTiff(List<File> data, File destFile) throws IOException {
        Box box = new Box();
        if (data.size() == 0) {
            return box;
        }

        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("tiff");

        if (!writers.hasNext()) {
            throw new RuntimeException("缺失Java图像工具库");
        }

        ImageWriter writer = writers.next();

        TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.US);
        IIOMetadata         streamMetadata = writer.getDefaultStreamMetadata(tiffWriteParam);

        ImageOutputStream ios = ImageIO.createImageOutputStream(destFile);
        writer.setOutput(ios);

        boolean      firstPage   = true;
        int          index       = 1;
        int          myFileIndex = 0;
        List<BoxRow> boxRowList  = new ArrayList<BoxRow>();
        // 获取tiff合成后在multi-tiff中的索引值，用以生成box文件
        for (File inputImage : data) {
            // 生成BoxRow对象
            BoxRow        boxRow        = new BoxRow(BoxRow.getValue(inputImage), myFileIndex);
            BufferedImage bufferedImage = ImageIO.read(inputImage);
            Rectangle     rectangle     = ImageUtils.getRectangleFromImage(bufferedImage);
            boxRow.setRectangle(rectangle);

            List<IIOImage> iioImages = getIIOImageList(inputImage);
            for (IIOImage iioImage : iioImages) {
                if (firstPage) {
                    writer.write(streamMetadata, iioImage, tiffWriteParam);
                    firstPage = false;
                } else {
                    writer.writeInsert(index++, iioImage, tiffWriteParam);
                }
            }
            boxRowList.add(boxRow);

            myFileIndex++;
        }
        box.setBoxRowList(boxRowList);

        ios.close();
        writer.dispose();

        return box;
    }

    /**
     * 获取文件名（不带有文件扩展名）
     *
     * @param str
     * @return
     */
    public static String stripExtension(String str) {
        if (str == null) {
            return null;
        }

        int pos = str.lastIndexOf(".");

        if (pos == -1) {
            return str;
        }

        return str.substring(0, pos);
    }

    /**
     * 从图像文件中解析出Rectangle对象
     *
     * @param bufferedImage
     * @return
     */
    public static Rectangle getRectangleFromImage(BufferedImage bufferedImage) {
        Rectangle rectangle = new Rectangle();
        rectangle.x = 0;
        rectangle.y = 0;
        rectangle.height = bufferedImage.getHeight();
        rectangle.width = bufferedImage.getWidth();

        return rectangle;
    }

    /**
     * 将Base64字符串数据解码为图片文件
     *
     * @param imageStr
     * @param path
     * @return 图片文件
     */
    public static File decodeImage(String imageStr, String path) {
        File imageFile = null;
        if (imageStr == null || imageStr.trim().length() == 0) {
            return imageFile;
        }

        /**
         * 过滤data:image/jpg;base64,前缀
         */
        imageStr = imageStr.replaceFirst("^data:image/[a-zA-Z]+;base64,", "");

        BASE64Decoder decoder = new BASE64Decoder();
        try {
            byte[] bytes = decoder.decodeBuffer(imageStr);
            for (int i = 0; i < bytes.length; i++) {
                if (bytes[i] < 0) {
                    bytes[i] += 256;
                }
            }

            // 获取图片格式，并给图片设置扩展名
            ImageInputStream imageInputStream = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
            String           formatName       = ImageIO.getImageReaders(imageInputStream).next().getFormatName();
            path = path + "." + formatName;

            OutputStream outputStream = new FileOutputStream(path);
            outputStream.write(bytes);
            outputStream.flush();
            outputStream.close();
            imageFile = new File(path);
        } catch (IOException e) {
            e.printStackTrace();
            return imageFile;
        }
        return imageFile;
    }

    /**
     * 将图片文件编码成Base64字符串数据
     *
     * @param path
     * @return
     */
    public static String encodeImage(String path) {
        InputStream inputStream = null;
        byte[]      data        = null;

        try {
            inputStream = new FileInputStream(path);
            data = new byte[inputStream.available()];
            inputStream.read(data);
            inputStream.close();
            // 解码
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(data);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        String imagePath = "/home/newcih/Screenshot from 2018-02-06 09-27-25.png";
        String content   = ImageUtils.encodeImage(imagePath);
        System.out.println(content);
    }

}
